import java.util.Arrays;

class EmptyException extends RuntimeException {
    public EmptyException() {
        //这是一个提示顺序表为空的异常
    }

    public EmptyException(String massage) {
        super(massage);
    }
}

class PosWrongfulException extends RuntimeException{
    public PosWrongfulException() {
        //PosWrongfulException 一个提示不合法的异常
    }

    public PosWrongfulException(String massage) {
        super(massage);
    }
}

class MyArrayList {
    private int[] elem; //未初始化的数组
    private int usedSize; //记录有效的数据个数
    public static final int DEFAULT_SIZE = 10;

    //构造方法
    public MyArrayList() {
        this.elem = new int[DEFAULT_SIZE];//数组大小为10个元素
    }

    //打印顺序表中所有的元素，这并不是顺序表中的方法，而是为了观看测试结果给出的
    public void disPlay() {
        for (int i = 0; i < this.usedSize; i++) {//usedSize是有效数据个数
            System.out.print(this.elem[i] + " "); //元素之间加上空格
        }
        System.out.println();//输出完后换行
    }

    //检查顺序表是否满了的方法
    public boolean isFull() {
        //size()是获取顺序表长度的方法

        /*if (size() >= this.elem.length) { //满了
            return true;
        }else { //没满
            return false;
        }*/

        //优化过后的写法 - 会自动比较出一个true || false
        return size() >= this.elem.length;
    }

    //默认在顺序表最后新增元素 - data是要新增的元素
    public void add(int data) {
        //1. 检查当前的顺序表是不是满了
        //isFull()方法中会有一个值来表示当前顺序表是不是满了
        if (isFull()) {
            //2. 如果满了 就要进行扩容
            //将elem扩容位原来的2倍
            this.elem = Arrays.copyOf(this.elem, 2 * this.elem.length);
        }

        //3.新增元素
        //当前usedSize(有效元素个数)的值就是顺序表末尾的下标 - 要想新增赋值即可
        this.elem[this.usedSize] = data;

        //4.有效元素个数加1 - usedSize
        this.usedSize++;
    }

    /**
     * 如果 pos 下标不合法就会抛出一个异常
     *
     */

    //在顺序表指定位置新增 - 在pos位置新增元素- data是要新增的元素
    //throws PosWrongfulException可以提示调用者这个地方可能会有一个异常
    public void add(int pos, int data) throws PosWrongfulException{
        //1.负数下标不可以
        //2.要存储的位置pos前面一定是有元素的
        //usedSize在这里指的是顺序表末尾的位置下标
        if (pos < 0 || pos > this.usedSize) { //pos是指定新增位置的下标
            System.out.println("位置不合法！！！");

            //抛一个异常
            throw new PosWrongfulException("位置不合法！！！");
        }
        if (isFull()) {
            //3.超过数组长度不可以
            //满了就扩容
            System.out.println("顺序表满了");
            this.elem = Arrays.copyOf(this.elem, 2 * this.elem.length);
        }

        //程序执行到这里就可以插入一个元素了
        //1.开始挪动数据
        //从顺序表末位位置开始向后移动，直到遇到 pos 位置
        for (int i = this.usedSize - 1; i >= pos; i--) { //usedSize-1指的是顺序表末位位置的下标
            this.elem[i + 1] =  this.elem[i];
        }

        //2.在顺序表中插入一个元素
        this.elem[pos] = data; //data是要插入个元素

        //3.顺序表元素加1 - usedSize
        this.usedSize++; //顺序表有效元素个数加一个
    }

    //判定是否包含某个元素 - toFind是我要判定的元素
    public boolean contains(int toFind) {
        //size()方法求的是顺序表的长度
        for (int i = 0; i < this.size(); i++) {
            if (this.elem[i] == toFind) {
                return true; //找到了
            }
        }
        return false;///没找到
    }

    //查找某个对应元素的位置 - toFind是我要查找的元素
    public int indexOf (int toFind) {
        //size()方法求的是顺序表的长度
        for (int i = 0; i < this.size(); i++) {
            //若顺序表存储的是引用数据类型，该怎么比较？要使用 equals()来比较
            if (this.elem[i] == toFind) {
                return i; //找到了 - 返回下标
            }
        }
        return -1;//没找到 - 返回-1
    }

    public boolean isEmpty() {
        //size()方法求的是顺序表有效元素个数
        return size() == 0;//根据比较的值来返回true或者false
    }

    //获取 pos 元素的位置
    public int get(int pos) {
        if (isEmpty()) {
            //顺序表有可能是空的 - 抛异常来提示
            throw new EmptyException("当前顺序表为空！！！");
        }
        if (pos < 0 || pos >= usedSize) {
            //查找位置的下标可能是负数 - 也可能超过了顺序表的长度 - 抛异常来提示
            throw new PosWrongfulException("get获取元素的时候，pos位置不合法！！！");
        }
        return this.elem[pos]; //此时pos下标就是要找的位置
    }

    //给 pos 位置的元素更新为 value
    public void set(int pos, int value) {
        //1.顺序表不是空的
        if (isEmpty()) {
            //顺序表有可能是空的 - 抛异常来提示
            //这里要注意的是此方法是用来更新的，即使是空间满了也不需要扩容
            throw new EmptyException("当前顺序表为空！！！");
        }

        //2.pos位置要合法 - 下标不为负数，不超过数组长度
        if (pos < 0 || pos >= usedSize) {
            //查找位置的下标可能是负数 - 也可能超过了顺序表的长度 - 抛异常来提示
            throw new PosWrongfulException("set获取元素的时候，pos位置不合法！！！");
        }

        //开始更新
        this.elem[pos] = value; //value是更新后的值
    }

    //删除第一次出现的关键字 Key - Key是多次出现的元素
    public void remove (int Key) {
        //1.空的顺序表没有 Key
        if (isEmpty()) {
            //因为作用是删除，即使是空表也不需要扩容
            throw new EmptyException("顺序表为空！！！");
        }
        int index = indexOf(Key);//查找Key位置的下标
        if (index == -1) {
            System.out.println("没有这个数字！！！");
            return;
        }

        //2.要先找到key，才能知道下标
        //数组是从要删除的元素开始遍历，直到遇到在数组末尾的有效数据元素结束
        for (int i = index; i < usedSize - 1; i++) {
            //3.挪动数据
            this.elem[i] = this.elem[i + 1];//将顺序表后一个元素向前一个元素的位置覆盖
        }

        //4，顺序表长度减1
        this.usedSize--;//顺序表长度减1
    }

    //获取顺序表长度
    public int size() {
        return this.usedSize;
    }

    //清空顺序表
    public void clear() {
        //如果顺序表存储的是引用类型的数据则要将表置为null
        /*for (int i = 0; i < usedSize; i++) { //0表示的是表的第一个元素，遍历完整个表结束
            this.elem[i] = null;//将每一个元素董志伟空
        }*/

        //如果是普通类型，则置为0
        this.usedSize = 0;
    }
}

public class TestList {
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();

        //测试add()方法
        myArrayList.add(1);//将顺序表中添加一个1元素
        myArrayList.add(2);
        myArrayList.add(3);
        myArrayList.disPlay();//调用打印方法定义顺序表中的所有元素

        //测试指定位置的add()方法
        try{
            myArrayList.add(2, 10);//将2下标的位置插入一个10
        }catch (PosWrongfulException e){ //包裹一下可能会抛出的异常
            e.printStackTrace();//如果有异常会提示
        }
        myArrayList.disPlay();//打印插入指定位置的顺序表
        System.out.println("================================");

        //判断contains()方法
        //在顺序表查找是否存在10和100这两个元素
        //表中存在10，不存在100 - 因为这一句代码:myArrayList.add(2, 10);
        System.out.println(myArrayList.contains(10));//输出true
        System.out.println(myArrayList.contains(100));//输出false

        //测试indexOf()方法
        System.out.println(myArrayList.indexOf(10));//输出10元素的下标 - 2
        System.out.println(myArrayList.indexOf(100));//输出100元素的下标 - 因为没有这个元素所以输出-1

        //测试get()方法
        try{
            //System.out.println(myArrayList.get(10));//获取10下标 - 由于顺序表没有10下标所以会抛异常
            System.out.println(myArrayList.get(1));//获取1下标 - 会输出2 - 因为当前表中1下标存储的数据是2
        }catch (PosWrongfulException e) {
            e.printStackTrace();//如果有异常会提示
        }

        //测试set()方法
        myArrayList.set(1, 99);//将1下标改为99
        myArrayList.disPlay();//打印当前顺序表

        //测试remove()方法
        myArrayList.remove(99);//将表中的99删除
        myArrayList.disPlay();//打印删除后的表

        //测试clear()方法
        myArrayList.clear();//清空
        myArrayList.disPlay();//打印清空后的表
    }
}